`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          CLK_PRD                 = 5;
localparam          DATA_BW                 = 8;
localparam          PRBS_N                  = 9;
localparam          PRBS_DW                 = ((PRBS_N>=DATA_BW) ? PRBS_N : DATA_BW);

localparam          AWGN_DW                 = 12;
localparam          CH_DW                   = 8;
localparam          CH_NUM                  = 16;    // 2<=CH_NUM<=16
localparam          GAIN_DW                 = 8;
localparam          GAIN_QW                 = 5;
localparam          SRC_PRBS_N              = 23;
localparam          CH_PRBS_N               = 11;

localparam          PRBS_INI                = 1'b0;   // 1'b0: all zeros is a normal state and all ones  is a dead state for prbs_dat; 
localparam          MSB_FIRST               = 1'b0;
localparam [PRBS_DW-1:0]    SEED            = 1;

reg                                         rst_n;
reg                                         clk;

reg                 [PRBS_DW-1:0]           prbs_data;

wire                                        out_vld;
wire                [DATA_BW-1:0]           out_dat;

initial begin:CRG
    rst_n=1'b0;
    clk=1'b0;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_prbs", 1);

    rgrs.wait_chks_done(100_000_000);
end

initial begin:GEN_PRBS
    prbs_data = 0;

    @(posedge rst_n);
    @(posedge clk);

    repeat(512) begin
        `U_DLY;
        prbs_data = prbs_nxt_f(prbs_data, PRBS_N, DATA_BW, 1'b0, 1'b1);

        @(posedge clk);
    end
    rgrs.one_chk_done("sch num is done.");
end

wire                                        awgn_vld;
wire        signed  [AWGN_DW-1:0]           awgn_dat;
wire                                        awgn_rdy;

awgn_prbs #(
        .AWGN_DW                        (AWGN_DW                        ),
        .CH_DW                          (CH_DW                          ),
        .CH_NUM                         (CH_NUM                         ),	// 2<=CH_NUM<=16
        .GAIN_DW                        (GAIN_DW                        ),
        .GAIN_QW                        (GAIN_QW                        ),
        .SRC_PRBS_N                     (SRC_PRBS_N                     ),
        .CH_PRBS_N                      (CH_PRBS_N                      )
) u_awgn ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),

        .awgn_vld                       (awgn_vld                       ),
        .awgn_dat                       (awgn_dat                       ),
        .awgn_rdy                       (awgn_rdy                       ),

        .cfg_gain                       ({3'h0, 5'h10}                  )
);

assign awgn_rdy = 1'b1;

reg  signed [15:0] ch_sum;
always@(*) begin:SUM
    integer i;

    ch_sum = 0;
    for (i=0; i<CH_NUM; i=i+1) begin
        ch_sum = ch_sum + $signed(u_awgn.ch_prbs_dat[i][0+:CH_DW]);
    end
end

prbs_gen #(
        .PRBS_N                         (PRBS_N                         ),
        .OUT_DW                         (DATA_BW                        ),
//        .SHIFT_N                        (1                              ),
        .PRBS_INI                       (PRBS_INI                       ),	// 1'b0: all zeros is a normal state and all ones  is a dead state for prbs_dat; 
        .MSB_FIRST                      (MSB_FIRST                      )
) u_prbs_gen ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .cfg_seed                       (SEED                           ),	// tie it to {PRBS_DW{PRBS_INI}}, if not used
        .cfg_clr                        (1'b0                           ),

        .prbs_dat                       (                               ),

        .out_vld                        (out_vld                        ),
        .out_dat                        (out_dat                        ),
        .out_rdy                        (1'b1                           )
);

prbs_chk #(
        .PRBS_N                         (PRBS_N                         ),
        .IN_DW                          (DATA_BW                        ),
//        .SHIFT_N                        (1                              ),
        .PRBS_INI                       (PRBS_INI                       ),	// 1'b0: all zeros is a normal state and all ones  is a dead state for prbs_dat; 
        .MSB_FIRST                      (MSB_FIRST                      ),
        .SYNC_NUM                       (4                              ),
        .LOS_NUM                        (8                              )
) u_prbs_chk ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .prbs_dat                       (                               ),

        .in_vld                         (out_vld                        ),
        .in_dat                         (out_dat                        ),

        .cfg_clr                        (1'b0                           ),
        .ptrn_sync                      (                               ),
        .prbs_err                       (                               )
);

wire                [DATA_BW-1:0]           dly_dat;

dly_mem #(
        .DW                             (DATA_BW                        ),
        .DEPTH                          (16                             ),
//        .MEM_STYLE                      ("TINY_MEM"                     ),
        .MEM_STYLE                      ("TPRAM"                        ),
        .EARLY_DATA                     ("ZERO"                         ),	// "ZERO"
        .ECC_MODE                       ("NONE"                         ) 	// no ECC
) u_dly_mem ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .id                             (out_dat                        ),	// data before delay
        .od                             (dly_dat                        ),	// actual delay is (cfg_dly+2)*cke + (mem_rd_latency-1)

        .cfg_dly                        (4'd14                          )	// 0<=cfg_dly<=DEPTH-2
);


`include "func_prbs.v"

endmodule

